Packages
library(plyr)
library(tidyverse)
library(here)
library(geojsonR)
library(janitor)
library(knitr)
library(lubridate)
library(mapview)
library(gbfs)
library(sf)
library(tmap)
library(tidycensus)
library(dplyr)
library(conflicted)
library(plotly)
conflicts_prefer(here::here)
conflicts_prefer(dplyr::rename)
conflicts_prefer(dplyr::filter)
conflicts_prefer(dplyr::mutate)
Reading the files.
Metro Station Entrances to map the location of metro, boarding data
to show how many people are using the metro station, and bikeshare to
show the number of people riding bikes.
All data is from the month September because there are no major
holidays, the weather is still decent enough for people to ride bikes,
and the number of tourists/ pleasure bike riders are reduced.
For the purpose of this project, we plan on focusing on the
commuters, and plan on creating more bike locations to better suit the
number of commuters.
metro <- FROM_GeoJson(here('data_raw', 'Metro_Station_Entrances_in_DC.geojson'))
metroRiders <- read.csv(here( 'Boardings by Route Table_Full Data_data.csv'))
metroLoc <- read.csv(here('data_raw', 'Metro_Stations_Regional.csv'))
sept_raw <- read_csv(here( '202309-capitalbikeshare-tripdata.csv'))
neigh = st_read(here("data_raw", "DC_Health_Planning_Neighborhoods.geojson")) %>% clean_names()
Cleaning Data
This filters the data so we are only getting entries for the weekdays
and not the weekends, appending location variables to station names, and
combining repeat stations with a summed amount of entries.
#metroLoc = metroLoc |>
#rename("X" = "ï..X")
metroAddy <- subset(metroLoc, select = c(NAME, ADDRESS, X, Y))|>
rename("Station" = "NAME", "Lon" = "X", "Lat" = "Y")
metroRiders$Time.Period = NULL
metroRiders$Day.of.Week = NULL
metroRiders$Holiday = NULL
metroRiders$Month = NULL
metroRiders$Year = NULL
metroRiders$Avg.Daily.Entries.Rounded = NULL
#metroRiders = metroRiders |>
#rename("Station" = "ï..Station")
metroR1 <- metroRiders |>
filter(Servicetype == "Weekday") |>
ddply("Station", numcolwise(sum))
METRO <- merge(x = metroR1, y = metroAddy, by = "Station")
glimpse(METRO)
Cleaning bike data
bikeR1 is the data set originated from September Bikeshare data. It
is filtered to keep the columns “started at”, “start lat” and
“start_lng”. Na.omit gets rid of everything null, and mutate adds the
date to when each bike ride started.
bikeR2 is a further filtering of bikeR1 where coordinates are added
so we can map out the bike riders starting location.
bikeR3 is the new data set where bikeR2 and neigh are joined.
bikeR1 = sept_raw %>% select(started_at, start_lat, start_lng) %>% na.omit() %>% mutate(start_date=as.Date(started_at)) %>% select(start_date, start_lat, start_lng)
bikeR2 = bikeR1 %>% st_as_sf(coords=c("start_lng", "start_lat"), crs=4326)
st_crs(neigh$geometry[1])
bikeR3 = bikeR2 %>% st_join(neigh)
#code for possible future mapping
#df1_s_sf = df1_s %>% st_as_sf(coords =c("start_lng", "start_lat"), crs = 4326)
Metro Map
The first part of this code chunk is converting the metro data frame
into a spatial data frame.
MetroMap2 is a filtration of MetroMap that joins the data set “neigh”
and omits any null values. Then a variable ‘code’ is added to the
numcolwise. There are 50 ‘codes’ created in this process. Then from
those codes, we will determine rideship for both bikes and metro.
MetroMap <- st_as_sf(METRO, coords = c("Lon", "Lat"), crs =4326)
MetroMap2 <- MetroMap %>%
st_join(neigh) %>% na.omit() %>%
ddply("code", numcolwise(sum))
More Filtering
neigh1 is the new data frame of “neigh” where code and geometry are
the chosen variables to be kept.
bike R4 is a further filtration of bikeR3, where start date, code,
geometry is kept and geometry column is dropped.
bikeR5 is another filter of neigh1, where bikeR4 is added (joined).
Additionally, each of the weekend dates are removed from the data set as
we chose to only look at weekday data.
neigh1 = neigh %>% select(code, geometry)
bikeR4 = bikeR3 %>% select(start_date, code, geometry) %>% st_drop_geometry()
bikeR5 = neigh1 %>% full_join(bikeR4) %>% filter(start_date != as.Date('2023-09-02')) %>% filter(start_date != as.Date('2023-09-03')) %>% filter(start_date != as.Date('2023-09-09')) %>% filter(start_date != as.Date('2023-09-10')) %>% filter(start_date != as.Date('2023-09-16')) %>% filter(start_date != as.Date('2023-09-17')) %>% filter(start_date != as.Date('2023-09-23')) %>% filter(start_date != as.Date('2023-09-24')) %>% filter(start_date != as.Date('2023-09-30'))
And More!
bikeR6 is a nre data frame where we took the bike data from set
bikeR5. bikeR6 has 51 codes and they are listed as observations. All
null values are ommitted.
bikeR7 takes the data from bikeR6 and keeps the code as well as
frequency and renames it to bike_freq.
#plot(neigh)
bikeR6 = data.frame(table(bikeR5$code)) %>% rename(code=Var1) %>% full_join(bikeR5) %>% select(code, Freq, geometry) %>% distinct() %>% na.omit()
bikeR7 = bikeR6 %>% select (code, Freq) %>% rename(bike_freq = Freq)
MetroMap3 = MetroMap2 %>% select(Entries, code) %>% rename(metro_freq = Entries)
metro_bike_df = bikeR7 %>% full_join(MetroMap3) %>% mutate(metro_freq = replace_na(metro_freq, 0))
#bikeR7 = bikeR5 %>% count(code, start_date)
#plot(bikeR6)
Last One!
bikeR8 takes bikeR6 and keeps the code and frequency. It also creates
a column called bike because all the data in this set is from bike
riders. We will use this column later when we make our visual.
MetroMap4 continues the filtration of MetroMap2 where entries (later
renamed to freq) and code are kept. Every data in this set is given the
variable ‘metro’ as they represent a metro rider.
bikeR8 = bikeR6 %>% select (code, Freq) %>% rename(freq = Freq) %>% mutate(transport = 'bike')
MetroMap4 = MetroMap2 %>% select(Entries, code) %>% rename(freq = Entries) %>% mutate(transport = 'metro')
code = c("N1", "N10", "N11", "N14", "N15", "N16", "N2", "N20", "N21", "N22", "N26", "N27", "N28", "N3", "N32", "N33", "N34", "N36", "N37", "N4", "N40", "N41", "N45", "N46", "N47", "N49", "N5", "N50", "N51", "N6", "N8")
freq = c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
transport = c('metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro')
metroExtra = data.frame(code, freq, transport)
MetroMap4 = MetroMap4 %>% rbind(metroExtra)
metro_bike_df2 = bikeR8 %>% full_join(MetroMap4)
Mapping Metro
This is a simple visual of the metro station locations in DC.
entrances=st_read(here("Metro_Station_Entrances_in_DC.geojson")) %>% clean_names()
class(entrances)
plot(entrances)
Mapping Bike Data
We create a gg plot of the data from above. The combined data set of
metro and bike riders (metro_bike_df2). We wanted to visualize the
number of people who are riding the metro vs using bikes in each of the
‘codes’.
charts <- ggplot(metro_bike_df2, aes(fill=transport, y=freq, x=code)) + geom_bar(position='dodge', stat='identity')
ggplotly(charts)
Recommednation:
Based on the data comparisons of metro entries and bike entries, we
would recommend that the bikeshare group look into increasing the amount
of bike stations in neighborhoods: n2, n5, n22, n28, n41 as these are
the neighborhoods with no metro stations being entered and already have
a solid group of bike riders, so increasing stations here would allow
ofr the most benefits for the bikeshare.
LS0tDQp0aXRsZTogIkZpbmFsIFByb2plY3QiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBQYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocGx5cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShnZW9qc29uUikNCmxpYnJhcnkoamFuaXRvcikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkgDQpsaWJyYXJ5KG1hcHZpZXcpDQpsaWJyYXJ5KGdiZnMpDQpsaWJyYXJ5KHNmKSANCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkodGlkeWNlbnN1cykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGNvbmZsaWN0ZWQpDQpsaWJyYXJ5KHBsb3RseSkNCmNvbmZsaWN0c19wcmVmZXIoaGVyZTo6aGVyZSkNCmNvbmZsaWN0c19wcmVmZXIoZHBseXI6OnJlbmFtZSkNCmNvbmZsaWN0c19wcmVmZXIoZHBseXI6OmZpbHRlcikNCmNvbmZsaWN0c19wcmVmZXIoZHBseXI6Om11dGF0ZSkNCg0KYGBgDQoNCiMjIFJlYWRpbmcgdGhlIGZpbGVzLg0KDQpNZXRybyBTdGF0aW9uIEVudHJhbmNlcyB0byBtYXAgdGhlIGxvY2F0aW9uIG9mIG1ldHJvLCBib2FyZGluZyBkYXRhIHRvIHNob3cgaG93IG1hbnkgcGVvcGxlIGFyZSB1c2luZyB0aGUgbWV0cm8gc3RhdGlvbiwgYW5kIGJpa2VzaGFyZSB0byBzaG93IHRoZSBudW1iZXIgb2YgcGVvcGxlIHJpZGluZyBiaWtlcy4NCg0KQWxsIGRhdGEgaXMgZnJvbSB0aGUgbW9udGggU2VwdGVtYmVyIGJlY2F1c2UgdGhlcmUgYXJlIG5vIG1ham9yIGhvbGlkYXlzLCB0aGUgd2VhdGhlciBpcyBzdGlsbCBkZWNlbnQgZW5vdWdoIGZvciBwZW9wbGUgdG8gcmlkZSBiaWtlcywgYW5kIHRoZSBudW1iZXIgb2YgdG91cmlzdHMvIHBsZWFzdXJlIGJpa2UgcmlkZXJzIGFyZSByZWR1Y2VkLg0KDQpGb3IgdGhlIHB1cnBvc2Ugb2YgdGhpcyBwcm9qZWN0LCB3ZSBwbGFuIG9uIGZvY3VzaW5nIG9uIHRoZSBjb21tdXRlcnMsIGFuZCBwbGFuIG9uIGNyZWF0aW5nIG1vcmUgYmlrZSBsb2NhdGlvbnMgdG8gYmV0dGVyIHN1aXQgdGhlIG51bWJlciBvZiBjb21tdXRlcnMuDQoNCmBgYHtyfQ0KbWV0cm8gPC0gRlJPTV9HZW9Kc29uKGhlcmUoJ2RhdGFfcmF3JywgJ01ldHJvX1N0YXRpb25fRW50cmFuY2VzX2luX0RDLmdlb2pzb24nKSkNCm1ldHJvUmlkZXJzIDwtIHJlYWQuY3N2KGhlcmUoICdCb2FyZGluZ3MgYnkgUm91dGUgVGFibGVfRnVsbCBEYXRhX2RhdGEuY3N2JykpDQptZXRyb0xvYyA8LSByZWFkLmNzdihoZXJlKCdkYXRhX3JhdycsICdNZXRyb19TdGF0aW9uc19SZWdpb25hbC5jc3YnKSkgDQoNCnNlcHRfcmF3IDwtIHJlYWRfY3N2KGhlcmUoICcyMDIzMDktY2FwaXRhbGJpa2VzaGFyZS10cmlwZGF0YS5jc3YnKSkNCg0KbmVpZ2ggPSBzdF9yZWFkKGhlcmUoImRhdGFfcmF3IiwgIkRDX0hlYWx0aF9QbGFubmluZ19OZWlnaGJvcmhvb2RzLmdlb2pzb24iKSkgJT4lIGNsZWFuX25hbWVzKCkNCg0KYGBgDQoNCiMjIENsZWFuaW5nIERhdGENCg0KVGhpcyBmaWx0ZXJzIHRoZSBkYXRhIHNvIHdlIGFyZSBvbmx5IGdldHRpbmcgZW50cmllcyBmb3IgdGhlIHdlZWtkYXlzIGFuZCBub3QgdGhlIHdlZWtlbmRzLCBhcHBlbmRpbmcgbG9jYXRpb24gdmFyaWFibGVzIHRvIHN0YXRpb24gbmFtZXMsIGFuZCBjb21iaW5pbmcgcmVwZWF0IHN0YXRpb25zIHdpdGggYSBzdW1tZWQgYW1vdW50IG9mIGVudHJpZXMuDQoNCmBgYHtyfQ0KI21ldHJvTG9jID0gbWV0cm9Mb2MgfD4gDQogICNyZW5hbWUoIlgiID0gIsOvLi5YIikNCg0KbWV0cm9BZGR5IDwtIHN1YnNldChtZXRyb0xvYywgc2VsZWN0ID0gYyhOQU1FLCBBRERSRVNTLCBYLCBZKSl8Pg0KICByZW5hbWUoIlN0YXRpb24iID0gIk5BTUUiLCAiTG9uIiA9ICJYIiwgIkxhdCIgPSAiWSIpDQoNCm1ldHJvUmlkZXJzJFRpbWUuUGVyaW9kID0gTlVMTA0KbWV0cm9SaWRlcnMkRGF5Lm9mLldlZWsgPSBOVUxMDQptZXRyb1JpZGVycyRIb2xpZGF5ID0gTlVMTA0KbWV0cm9SaWRlcnMkTW9udGggPSBOVUxMDQptZXRyb1JpZGVycyRZZWFyID0gTlVMTA0KbWV0cm9SaWRlcnMkQXZnLkRhaWx5LkVudHJpZXMuUm91bmRlZCA9IE5VTEwNCg0KI21ldHJvUmlkZXJzID0gbWV0cm9SaWRlcnMgfD4NCiAjcmVuYW1lKCJTdGF0aW9uIiA9ICLDry4uU3RhdGlvbiIpDQoNCm1ldHJvUjEgPC0gbWV0cm9SaWRlcnMgfD4NCiAgZmlsdGVyKFNlcnZpY2V0eXBlID09ICJXZWVrZGF5IikgfD4NCiAgZGRwbHkoIlN0YXRpb24iLCBudW1jb2x3aXNlKHN1bSkpDQoNCk1FVFJPIDwtIG1lcmdlKHggPSBtZXRyb1IxLCB5ID0gbWV0cm9BZGR5LCBieSA9ICJTdGF0aW9uIikNCg0KZ2xpbXBzZShNRVRSTykNCg0KYGBgDQoNCiMjIENsZWFuaW5nIGJpa2UgZGF0YQ0KDQpiaWtlUjEgaXMgdGhlIGRhdGEgc2V0IG9yaWdpbmF0ZWQgZnJvbSBTZXB0ZW1iZXIgQmlrZXNoYXJlIGRhdGEuIEl0IGlzIGZpbHRlcmVkIHRvIGtlZXAgdGhlIGNvbHVtbnMgInN0YXJ0ZWQgYXQiLCAic3RhcnQgbGF0IiBhbmQgInN0YXJ0X2xuZyIuIE5hLm9taXQgZ2V0cyByaWQgb2YgZXZlcnl0aGluZyBudWxsLCBhbmQgbXV0YXRlIGFkZHMgdGhlIGRhdGUgdG8gd2hlbiBlYWNoIGJpa2UgcmlkZSBzdGFydGVkLg0KDQpiaWtlUjIgaXMgYSBmdXJ0aGVyIGZpbHRlcmluZyBvZiBiaWtlUjEgd2hlcmUgY29vcmRpbmF0ZXMgYXJlIGFkZGVkIHNvIHdlIGNhbiBtYXAgb3V0IHRoZSBiaWtlIHJpZGVycyBzdGFydGluZyBsb2NhdGlvbi4NCg0KYmlrZVIzIGlzIHRoZSBuZXcgZGF0YSBzZXQgd2hlcmUgYmlrZVIyIGFuZCBuZWlnaCBhcmUgam9pbmVkLiANCg0KYGBge3J9DQpiaWtlUjEgPSBzZXB0X3JhdyAlPiUgc2VsZWN0KHN0YXJ0ZWRfYXQsIHN0YXJ0X2xhdCwgc3RhcnRfbG5nKSAlPiUgbmEub21pdCgpICU+JSBtdXRhdGUoc3RhcnRfZGF0ZT1hcy5EYXRlKHN0YXJ0ZWRfYXQpKSAlPiUgc2VsZWN0KHN0YXJ0X2RhdGUsIHN0YXJ0X2xhdCwgc3RhcnRfbG5nKQ0KDQpiaWtlUjIgPSBiaWtlUjEgJT4lIHN0X2FzX3NmKGNvb3Jkcz1jKCJzdGFydF9sbmciLCAic3RhcnRfbGF0IiksIGNycz00MzI2KQ0KDQpzdF9jcnMobmVpZ2gkZ2VvbWV0cnlbMV0pDQoNCmJpa2VSMyA9IGJpa2VSMiAlPiUgc3Rfam9pbihuZWlnaCkNCg0KDQogDQojY29kZSBmb3IgcG9zc2libGUgZnV0dXJlIG1hcHBpbmcgDQojZGYxX3Nfc2YgPSBkZjFfcyAlPiUgc3RfYXNfc2YoY29vcmRzID1jKCJzdGFydF9sbmciLCAic3RhcnRfbGF0IiksIGNycyA9IDQzMjYpDQpgYGANCg0KDQojIyBNZXRybyBNYXANCg0KVGhlIGZpcnN0IHBhcnQgb2YgdGhpcyBjb2RlIGNodW5rIGlzIGNvbnZlcnRpbmcgdGhlIG1ldHJvIGRhdGEgZnJhbWUgaW50byBhIHNwYXRpYWwgZGF0YSBmcmFtZS4gDQoNCk1ldHJvTWFwMiBpcyBhIGZpbHRyYXRpb24gb2YgTWV0cm9NYXAgdGhhdCBqb2lucyB0aGUgZGF0YSBzZXQgIm5laWdoIiBhbmQgb21pdHMgYW55IG51bGwgdmFsdWVzLiBUaGVuIGEgdmFyaWFibGUgJ2NvZGUnIGlzIGFkZGVkIHRvIHRoZSBudW1jb2x3aXNlLiBUaGVyZSBhcmUgNTAgJ2NvZGVzJyBjcmVhdGVkIGluIHRoaXMgcHJvY2Vzcy4gVGhlbiBmcm9tIHRob3NlIGNvZGVzLCB3ZSB3aWxsIGRldGVybWluZSByaWRlc2hpcCBmb3IgYm90aCBiaWtlcyBhbmQgbWV0cm8uDQoNCmBgYHtyfQ0KTWV0cm9NYXAgPC0gc3RfYXNfc2YoTUVUUk8sIGNvb3JkcyA9IGMoIkxvbiIsICJMYXQiKSwgY3JzID00MzI2KQ0KDQpNZXRyb01hcDIgPC0gTWV0cm9NYXAgJT4lDQogIHN0X2pvaW4obmVpZ2gpICU+JSBuYS5vbWl0KCkgJT4lDQogIGRkcGx5KCJjb2RlIiwgbnVtY29sd2lzZShzdW0pKQ0KYGBgDQoNCg0KIyMgTW9yZSBGaWx0ZXJpbmcNCg0KbmVpZ2gxIGlzIHRoZSBuZXcgZGF0YSBmcmFtZSBvZiAibmVpZ2giIHdoZXJlIGNvZGUgYW5kIGdlb21ldHJ5IGFyZSB0aGUgY2hvc2VuIHZhcmlhYmxlcyB0byBiZSBrZXB0Lg0KDQpiaWtlIFI0IGlzIGEgZnVydGhlciBmaWx0cmF0aW9uIG9mIGJpa2VSMywgd2hlcmUgc3RhcnQgZGF0ZSwgY29kZSwgZ2VvbWV0cnkgaXMga2VwdCBhbmQgZ2VvbWV0cnkgY29sdW1uIGlzIGRyb3BwZWQuDQoNCmJpa2VSNSBpcyBhbm90aGVyIGZpbHRlciBvZiBuZWlnaDEsIHdoZXJlIGJpa2VSNCBpcyBhZGRlZCAoam9pbmVkKS4gQWRkaXRpb25hbGx5LCBlYWNoIG9mIHRoZSB3ZWVrZW5kIGRhdGVzIGFyZSByZW1vdmVkIGZyb20gdGhlIGRhdGEgc2V0IGFzIHdlIGNob3NlIHRvIG9ubHkgbG9vayBhdCB3ZWVrZGF5IGRhdGEuDQoNCmBgYHtyfQ0KDQpuZWlnaDEgPSBuZWlnaCAlPiUgc2VsZWN0KGNvZGUsIGdlb21ldHJ5KQ0KDQpiaWtlUjQgPSBiaWtlUjMgJT4lIHNlbGVjdChzdGFydF9kYXRlLCBjb2RlLCBnZW9tZXRyeSkgJT4lIHN0X2Ryb3BfZ2VvbWV0cnkoKQ0KDQpiaWtlUjUgPSBuZWlnaDEgJT4lIGZ1bGxfam9pbihiaWtlUjQpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTAyJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTAzJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTA5JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTEwJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTE2JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTE3JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTIzJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTI0JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTMwJykpDQpgYGANCiMjIEFuZCBNb3JlIQ0KDQpiaWtlUjYgaXMgYSBucmUgZGF0YSBmcmFtZSB3aGVyZSB3ZSB0b29rIHRoZSBiaWtlIGRhdGEgZnJvbSBzZXQgYmlrZVI1LiBiaWtlUjYgaGFzIDUxIGNvZGVzIGFuZCB0aGV5IGFyZSBsaXN0ZWQgYXMgb2JzZXJ2YXRpb25zLiBBbGwgbnVsbCB2YWx1ZXMgYXJlIG9tbWl0dGVkLg0KDQpiaWtlUjcgdGFrZXMgdGhlIGRhdGEgZnJvbSBiaWtlUjYgYW5kIGtlZXBzIHRoZSBjb2RlIGFzIHdlbGwgYXMgZnJlcXVlbmN5IGFuZCByZW5hbWVzIGl0IHRvIGJpa2VfZnJlcS4gDQoNCmBgYHtyfQ0KI3Bsb3QobmVpZ2gpDQoNCmJpa2VSNiA9IGRhdGEuZnJhbWUodGFibGUoYmlrZVI1JGNvZGUpKSAlPiUgcmVuYW1lKGNvZGU9VmFyMSkgJT4lIGZ1bGxfam9pbihiaWtlUjUpICU+JSBzZWxlY3QoY29kZSwgRnJlcSwgZ2VvbWV0cnkpICU+JSBkaXN0aW5jdCgpICU+JSBuYS5vbWl0KCkNCg0KYmlrZVI3ID0gYmlrZVI2ICU+JSBzZWxlY3QgKGNvZGUsIEZyZXEpICU+JSByZW5hbWUoYmlrZV9mcmVxID0gRnJlcSkNCg0KTWV0cm9NYXAzID0gTWV0cm9NYXAyICU+JSBzZWxlY3QoRW50cmllcywgY29kZSkgJT4lIHJlbmFtZShtZXRyb19mcmVxID0gRW50cmllcykNCg0KbWV0cm9fYmlrZV9kZiA9IGJpa2VSNyAlPiUgZnVsbF9qb2luKE1ldHJvTWFwMykgJT4lIG11dGF0ZShtZXRyb19mcmVxID0gcmVwbGFjZV9uYShtZXRyb19mcmVxLCAwKSkNCg0KI2Jpa2VSNyA9IGJpa2VSNSAlPiUgY291bnQoY29kZSwgc3RhcnRfZGF0ZSkNCg0KI3Bsb3QoYmlrZVI2KQ0KYGBgDQojIyBMYXN0IE9uZSENCg0KYmlrZVI4IHRha2VzIGJpa2VSNiBhbmQga2VlcHMgdGhlIGNvZGUgYW5kIGZyZXF1ZW5jeS4gSXQgYWxzbyBjcmVhdGVzIGEgY29sdW1uIGNhbGxlZCBiaWtlIGJlY2F1c2UgYWxsIHRoZSBkYXRhIGluIHRoaXMgc2V0IGlzIGZyb20gYmlrZSByaWRlcnMuIFdlIHdpbGwgdXNlIHRoaXMgY29sdW1uIGxhdGVyIHdoZW4gd2UgbWFrZSBvdXIgdmlzdWFsLiANCg0KTWV0cm9NYXA0IGNvbnRpbnVlcyB0aGUgZmlsdHJhdGlvbiBvZiBNZXRyb01hcDIgd2hlcmUgZW50cmllcyAobGF0ZXIgcmVuYW1lZCB0byBmcmVxKSBhbmQgY29kZSBhcmUga2VwdC4gRXZlcnkgZGF0YSBpbiB0aGlzIHNldCBpcyBnaXZlbiB0aGUgdmFyaWFibGUgJ21ldHJvJyBhcyB0aGV5IHJlcHJlc2VudCBhIG1ldHJvIHJpZGVyLg0KDQpgYGB7cn0NCmJpa2VSOCA9IGJpa2VSNiAlPiUgc2VsZWN0IChjb2RlLCBGcmVxKSAlPiUgcmVuYW1lKGZyZXEgPSBGcmVxKSAlPiUgbXV0YXRlKHRyYW5zcG9ydCA9ICdiaWtlJykNCg0KTWV0cm9NYXA0ID0gTWV0cm9NYXAyICU+JSBzZWxlY3QoRW50cmllcywgY29kZSkgJT4lIHJlbmFtZShmcmVxID0gRW50cmllcykgJT4lIG11dGF0ZSh0cmFuc3BvcnQgPSAnbWV0cm8nKQ0KDQpjb2RlID0gYygiTjEiLCAiTjEwIiwgIk4xMSIsICJOMTQiLCAiTjE1IiwgIk4xNiIsICJOMiIsICJOMjAiLCAiTjIxIiwgIk4yMiIsICJOMjYiLCAiTjI3IiwgIk4yOCIsICJOMyIsICJOMzIiLCAiTjMzIiwgIk4zNCIsICJOMzYiLCAiTjM3IiwgIk40IiwgIk40MCIsICJONDEiLCAiTjQ1IiwgIk40NiIsICJONDciLCAiTjQ5IiwgIk41IiwgIk41MCIsICJONTEiLCAiTjYiLCAiTjgiKQ0KDQpmcmVxID0gYygwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwKQ0KDQp0cmFuc3BvcnQgPSBjKCdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycpDQoNCm1ldHJvRXh0cmEgPSBkYXRhLmZyYW1lKGNvZGUsIGZyZXEsIHRyYW5zcG9ydCkNCg0KTWV0cm9NYXA0ID0gTWV0cm9NYXA0ICU+JSByYmluZChtZXRyb0V4dHJhKQ0KDQptZXRyb19iaWtlX2RmMiA9IGJpa2VSOCAlPiUgZnVsbF9qb2luKE1ldHJvTWFwNCkNCg0KYGBgDQoNCg0KIyMgTWFwcGluZyBNZXRybw0KDQpUaGlzIGlzIGEgc2ltcGxlIHZpc3VhbCBvZiB0aGUgbWV0cm8gc3RhdGlvbiBsb2NhdGlvbnMgaW4gREMuDQoNCmBgYHtyfQ0KZW50cmFuY2VzPXN0X3JlYWQoaGVyZSgiTWV0cm9fU3RhdGlvbl9FbnRyYW5jZXNfaW5fREMuZ2VvanNvbiIpKSAlPiUgY2xlYW5fbmFtZXMoKQ0KDQpjbGFzcyhlbnRyYW5jZXMpDQoNCnBsb3QoZW50cmFuY2VzKQ0KYGBgDQoNCiMjIE1hcHBpbmcgQmlrZSBEYXRhDQoNCldlIGNyZWF0ZSBhIGdnIHBsb3Qgb2YgdGhlIGRhdGEgZnJvbSBhYm92ZS4gVGhlIGNvbWJpbmVkIGRhdGEgc2V0IG9mIG1ldHJvIGFuZCBiaWtlIHJpZGVycyAobWV0cm9fYmlrZV9kZjIpLiBXZSB3YW50ZWQgdG8gdmlzdWFsaXplIHRoZSBudW1iZXIgb2YgcGVvcGxlIHdobyBhcmUgcmlkaW5nIHRoZSBtZXRybyB2cyB1c2luZyBiaWtlcyBpbiBlYWNoIG9mIHRoZSAnY29kZXMnLiANCg0KYGBge3J9DQpjaGFydHMgPC0gZ2dwbG90KG1ldHJvX2Jpa2VfZGYyLCBhZXMoZmlsbD10cmFuc3BvcnQsIHk9ZnJlcSwgeD1jb2RlKSkgKyBnZW9tX2Jhcihwb3NpdGlvbj0nZG9kZ2UnLCBzdGF0PSdpZGVudGl0eScpDQoNCmdncGxvdGx5KGNoYXJ0cykNCmBgYA0KDQojIyBSZWNvbW1lZG5hdGlvbjoNCkJhc2VkIG9uIHRoZSBkYXRhIGNvbXBhcmlzb25zIG9mIG1ldHJvIGVudHJpZXMgYW5kIGJpa2UgZW50cmllcywgd2Ugd291bGQgcmVjb21tZW5kIHRoYXQgdGhlIGJpa2VzaGFyZSBncm91cCBsb29rIGludG8gaW5jcmVhc2luZyB0aGUgYW1vdW50IG9mIGJpa2Ugc3RhdGlvbnMgaW4gbmVpZ2hib3Job29kczogbjIsIG41LCBuMjIsIG4yOCwgbjQxIGFzIHRoZXNlIGFyZSB0aGUgbmVpZ2hib3Job29kcyB3aXRoIG5vIG1ldHJvIHN0YXRpb25zIGJlaW5nIGVudGVyZWQgYW5kIGFscmVhZHkgaGF2ZSBhIHNvbGlkIGdyb3VwIG9mIGJpa2UgcmlkZXJzLCBzbyBpbmNyZWFzaW5nIHN0YXRpb25zIGhlcmUgd291bGQgYWxsb3cgb2ZyIHRoZSBtb3N0IGJlbmVmaXRzIGZvciB0aGUgYmlrZXNoYXJlLg==